
#ifndef __LIBERTY_ENGINE_XML_SERIALIZER_H__
#define __LIBERTY_ENGINE_XML_SERIALIZER_H__

#include <Liberty3D/Liberty3D.h>
#include <Liberty3D/Engine/XML/INode.h>
#include <Liberty3D/Engine/ISerializable.h>
#include <Liberty3D/Engine/ISerializer.h>

#include <list>
#include <vector>

namespace Liberty { namespace Engine { namespace Xml {

    class Reader : public ISerializer {
    protected:
        enum Status {
            FirstCall,
            Normal,
            Collection,
            Dictionary,
            DictionaryValue
        };

        enum Status                         _status;
        std::vector<enum Status>            _statuses;

        ISerializableFactory* _factory;
        bool                  _factoryDelete;

        std::vector<std::shared_ptr<ISerializable>> _objects;
        std::shared_ptr<INode>                      _objectsNode;
        std::vector<std::shared_ptr<INode>>         _stack;
        std::shared_ptr<INode>                      _current;

    public:
        Reader(std::shared_ptr<INode> node, ISerializableFactory* factory, bool factoryDelete = false);
        virtual ~Reader();

    public:
        virtual bool isReading() const;

    public:
        virtual bool serialize(const char* name, bool&               v, bool                    dv = false,         bool mandatory = false);
        virtual bool serialize(const char* name, int&                v, int                     dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, unsigned int&       v, unsigned int            dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, float&              v, float                   dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, double&             v, double                  dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, std::string&        v, const std::string&      dv = std::string(), bool mandatory = false);

#if defined(__LP64__)
        virtual bool serialize(const char* name, long&               v, long                    dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, unsigned long&      v, unsigned long           dv = 0,             bool mandatory = false);
#else
        virtual bool serialize(const char* name, long long&          v, long long               dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, unsigned long long& v, unsigned long long      dv = 0,             bool mandatory = false);
#endif

    public:
        virtual std::shared_ptr<ISerializable> readObject(const char* name);
        virtual void writeObject(const char* name, const std::shared_ptr<ISerializable>&);
        
        virtual size_t beginCollection(const char* name);
        virtual void   endCollection  (const char* name);

        virtual size_t beginDictionary(const char* name);
        virtual void   endDictionary  (const char* name);

        virtual void beginStruct(const char* name, const char* type);
        virtual void endStruct  (const char* name, const char* type);

        virtual void close();

    protected:
        void readObjects();
        std::string getValue(const std::shared_ptr<INode>&);
        std::shared_ptr<INode> getNode(const char* name);

        template <typename T, typename Pred>
        bool serializePrimitive(const char* name, T& v, T dv, bool mandatory, Pred);
    };

    class Writer : public ISerializer {
    protected:
        enum Status {
            Normal,
            Collection,
            Dictionary
        };

        enum Status                         _status;
        std::vector<enum Status>            _statuses;
        int                                 _dictionaryPair;
        std::vector<int>                    _dictionaryPairs;
        std::shared_ptr<INode>              _doc;
        std::vector<std::shared_ptr<INode>> _stack;
        std::shared_ptr<INode>              _current;

        std::vector<std::shared_ptr<ISerializable>> _objects;
        size_t                                      _objectIt;
        size_t                                      _currentObject;

    public:
        Writer();

    public:
        virtual bool isReading() const;

    public:
        inline std::shared_ptr<INode> document() const { return _doc; }

    public:
        virtual bool serialize(const char* name, bool&               v, bool                    dv = false,         bool mandatory = false);
        virtual bool serialize(const char* name, int&                v, int                     dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, unsigned int&       v, unsigned int            dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, float&              v, float                   dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, double&             v, double                  dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, std::string&        v, const std::string&      dv = std::string(), bool mandatory = false);

#if defined(__LP64__)
        virtual bool serialize(const char* name, long&               v, long                    dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, unsigned long&      v, unsigned long           dv = 0,             bool mandatory = false);
#else
        virtual bool serialize(const char* name, long long&          v, long long               dv = 0,             bool mandatory = false);
        virtual bool serialize(const char* name, unsigned long long& v, unsigned long long      dv = 0,             bool mandatory = false);
#endif

        virtual bool serialize(const char* name, Uuid& v, bool mandatory);
        
    public:
        virtual std::shared_ptr<ISerializable> readObject(const char* name);
        virtual void writeObject(const char* name, const std::shared_ptr<ISerializable>&);
        
        virtual size_t beginCollection(const char* name);
        virtual void   endCollection  (const char* name);

        virtual size_t beginDictionary(const char* name);
        virtual void   endDictionary  (const char* name);

        virtual void beginStruct(const char* name, const char* type);
        virtual void endStruct  (const char* name, const char* type);

        virtual void close();

    protected:
        std::shared_ptr<INode> getValue(const char* name, bool clear, bool create);
        void writePendingObjects();
    };

}}}

#endif
